Skip to content

Conversation

@bdbch
Copy link
Member

@bdbch bdbch commented Sep 5, 2025

Changes Overview

This pull request introduces a new, optional React integration for Tiptap, providing a declarative <Tiptap /> component that simplifies editor setup in React applications. This is an additive change, offering a more ergonomic, component-first API while keeping the existing imperative API fully supported for this major version. The update also includes minor robustness improvements in the core command logic.

With this new approach, we can later deprecate the current ways of setting up an editor that can be confusing and allows multiple ways that can lead to implementation errors.

Example:

import { Tiptap, useEditor, useTiptap } from '@tiptap/react'

function MyEditor() {
  const editor = useEditor({ extensions: [StarterKit], content: '<h1>Hello from Tiptap</h1>' })

  return (
    <Tiptap instance={editor}>
      <Tiptap.Content />
      <Tiptap.BubbleMenu>My Bubble Menu</Tiptap.BubbleMenu>
      <Tiptap.FloatingMenu>My Floating Menu</Tiptap.FloatingMenu>
      <MenuBar /> {/* MenuBar can use the new `useTiptap` hook to read the editor instance from context */}
    </Tiptap>
  )
}

function MenuBar() {
  const { editor } = useTiptap()

  return (
    <div>
      <button onClick={() => editor.chain().focus().toggleBold().run()}>Bold</button>
      <button onClick={() => editor.chain().focus().toggleItalic().run()}>Italic</button>
      <button onClick={() => editor.chain().focus().toggleStrike().run()}>Strike</button>
    </div>
  )
}

As you can see, this approach automatically provides a Context for all sub-components, that components can hook in.

  • <Tiptap /> - The wrapper that provides context
  • <Tiptap.Loading /> - A loading wrapper that can be used to render a loading spinner / message while the editor is initializing, setting up. Future plan is to wrap this together with collaborative features to make sure editors are only rendered when everything is initialized
  • <Tiptap.Content /> - The replacement for <EditorContent editor={editor} />
  • <Tiptap.BubbleMenu /> - The replacement for <BubbleMenu editor={editor} />
  • <Tiptap.FloatingMenu /> - The replacement for <FloatingMenu editor={editor} />
  • useTiptap() - A hook that can be used in sub-components to retrieve the Tiptap editor instance from children
    • const { editor } = useTiptap()
  • useTiptapState(selectorFn) - A replacement for useEditorState which can be used to directly retrieve editor state from the current editor

Implementation Approach

React integration and API improvements:

  • Added a new Tiptap component and related context/hooks (TiptapContext, useTiptap, useTiptapState) to packages/react/src/Tiptap.tsx, enabling declarative, prop-driven editor setup and composition in React apps. This includes subcomponents for content, loading state, and menus.
  • Exported the new Tiptap component and related utilities from the package entry point (packages/react/src/index.ts).
  • Added a changeset documenting the new React integration, migration guidance, and deprecation plans for the legacy setup.

Core robustness:

  • Improved error handling in the focus command (packages/core/src/commands/focus.ts) to gracefully handle cases where the editor view is not yet mounted, avoiding runtime errors.

Additional Notes

  • We will need to upgrade all demos later down the line

Checklist

  • I have created a changeset for this PR if necessary.
  • My changes do not break the library.
  • I have added tests where applicable.
  • I have followed the project guidelines.
  • I have fixed any lint issues.

@changeset-bot
Copy link

changeset-bot bot commented Sep 5, 2025

🦋 Changeset detected

Latest commit: e17bf4b

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 69 packages
Name Type
@tiptap/react Major
@tiptap/extension-drag-handle-react Major
@tiptap/core Major
@tiptap/extension-blockquote Major
@tiptap/extension-bold Major
@tiptap/extension-bubble-menu Major
@tiptap/extension-bullet-list Major
@tiptap/extension-code-block-lowlight Major
@tiptap/extension-code-block Major
@tiptap/extension-code Major
@tiptap/extension-collaboration-caret Major
@tiptap/extension-collaboration Major
@tiptap/extension-color Major
@tiptap/extension-details Major
@tiptap/extension-document Major
@tiptap/extension-drag-handle-vue-2 Major
@tiptap/extension-drag-handle-vue-3 Major
@tiptap/extension-drag-handle Major
@tiptap/extension-emoji Major
@tiptap/extension-file-handler Major
@tiptap/extension-floating-menu Major
@tiptap/extension-font-family Major
@tiptap/extension-hard-break Major
@tiptap/extension-heading Major
@tiptap/extension-highlight Major
@tiptap/extension-horizontal-rule Major
@tiptap/extension-image Major
@tiptap/extension-invisible-characters Major
@tiptap/extension-italic Major
@tiptap/extension-link Major
@tiptap/extension-list Major
@tiptap/extension-mathematics Major
@tiptap/extension-mention Major
@tiptap/extension-node-range Major
@tiptap/extension-ordered-list Major
@tiptap/extension-paragraph Major
@tiptap/extension-strike Major
@tiptap/extension-subscript Major
@tiptap/extension-superscript Major
@tiptap/extension-table-of-contents Major
@tiptap/extension-table Major
@tiptap/extension-text-align Major
@tiptap/extension-text-style Major
@tiptap/extension-text Major
@tiptap/extension-typography Major
@tiptap/extension-underline Major
@tiptap/extension-unique-id Major
@tiptap/extension-youtube Major
@tiptap/extensions Major
@tiptap/html Major
@tiptap/pm Major
@tiptap/starter-kit Major
@tiptap/static-renderer Major
@tiptap/suggestion Major
@tiptap/vue-2 Major
@tiptap/vue-3 Major
@tiptap/extension-character-count Major
@tiptap/extension-dropcursor Major
@tiptap/extension-focus Major
@tiptap/extension-gapcursor Major
@tiptap/extension-history Major
@tiptap/extension-list-item Major
@tiptap/extension-list-keymap Major
@tiptap/extension-placeholder Major
@tiptap/extension-table-cell Major
@tiptap/extension-table-header Major
@tiptap/extension-table-row Major
@tiptap/extension-task-item Major
@tiptap/extension-task-list Major

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@netlify
Copy link

netlify bot commented Sep 5, 2025

Deploy Preview for tiptap-embed ready!

Name Link
🔨 Latest commit e17bf4b
🔍 Latest deploy log https://app.netlify.com/projects/tiptap-embed/deploys/68bb712cb3be6a0008d72c3d
😎 Deploy Preview https://deploy-preview-6917--tiptap-embed.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@pkg-pr-new
Copy link

pkg-pr-new bot commented Sep 5, 2025

Open in StackBlitz

@tiptap/extension-character-count

npm i https://pkg.pr.new/@tiptap/extension-character-count@6917

@tiptap/extension-dropcursor

npm i https://pkg.pr.new/@tiptap/extension-dropcursor@6917

@tiptap/extension-gapcursor

npm i https://pkg.pr.new/@tiptap/extension-gapcursor@6917

@tiptap/extension-focus

npm i https://pkg.pr.new/@tiptap/extension-focus@6917

@tiptap/extension-history

npm i https://pkg.pr.new/@tiptap/extension-history@6917

@tiptap/extension-list-keymap

npm i https://pkg.pr.new/@tiptap/extension-list-keymap@6917

@tiptap/extension-list-item

npm i https://pkg.pr.new/@tiptap/extension-list-item@6917

@tiptap/extension-placeholder

npm i https://pkg.pr.new/@tiptap/extension-placeholder@6917

@tiptap/extension-table-header

npm i https://pkg.pr.new/@tiptap/extension-table-header@6917

@tiptap/extension-table-cell

npm i https://pkg.pr.new/@tiptap/extension-table-cell@6917

@tiptap/extension-table-row

npm i https://pkg.pr.new/@tiptap/extension-table-row@6917

@tiptap/extension-task-item

npm i https://pkg.pr.new/@tiptap/extension-task-item@6917

@tiptap/extension-task-list

npm i https://pkg.pr.new/@tiptap/extension-task-list@6917

@tiptap/extension-blockquote

npm i https://pkg.pr.new/@tiptap/extension-blockquote@6917

@tiptap/extension-bold

npm i https://pkg.pr.new/@tiptap/extension-bold@6917

@tiptap/core

npm i https://pkg.pr.new/@tiptap/core@6917

@tiptap/extension-bubble-menu

npm i https://pkg.pr.new/@tiptap/extension-bubble-menu@6917

@tiptap/extension-bullet-list

npm i https://pkg.pr.new/@tiptap/extension-bullet-list@6917

@tiptap/extension-code-block

npm i https://pkg.pr.new/@tiptap/extension-code-block@6917

@tiptap/extension-code

npm i https://pkg.pr.new/@tiptap/extension-code@6917

@tiptap/extension-code-block-lowlight

npm i https://pkg.pr.new/@tiptap/extension-code-block-lowlight@6917

@tiptap/extension-collaboration

npm i https://pkg.pr.new/@tiptap/extension-collaboration@6917

@tiptap/extension-collaboration-caret

npm i https://pkg.pr.new/@tiptap/extension-collaboration-caret@6917

@tiptap/extension-color

npm i https://pkg.pr.new/@tiptap/extension-color@6917

@tiptap/extension-details

npm i https://pkg.pr.new/@tiptap/extension-details@6917

@tiptap/extension-document

npm i https://pkg.pr.new/@tiptap/extension-document@6917

@tiptap/extension-drag-handle

npm i https://pkg.pr.new/@tiptap/extension-drag-handle@6917

@tiptap/extension-drag-handle-react

npm i https://pkg.pr.new/@tiptap/extension-drag-handle-react@6917

@tiptap/extension-drag-handle-vue-3

npm i https://pkg.pr.new/@tiptap/extension-drag-handle-vue-3@6917

@tiptap/extension-drag-handle-vue-2

npm i https://pkg.pr.new/@tiptap/extension-drag-handle-vue-2@6917

@tiptap/extension-emoji

npm i https://pkg.pr.new/@tiptap/extension-emoji@6917

@tiptap/extension-file-handler

npm i https://pkg.pr.new/@tiptap/extension-file-handler@6917

@tiptap/extension-floating-menu

npm i https://pkg.pr.new/@tiptap/extension-floating-menu@6917

@tiptap/extension-font-family

npm i https://pkg.pr.new/@tiptap/extension-font-family@6917

@tiptap/extension-hard-break

npm i https://pkg.pr.new/@tiptap/extension-hard-break@6917

@tiptap/extension-highlight

npm i https://pkg.pr.new/@tiptap/extension-highlight@6917

@tiptap/extension-heading

npm i https://pkg.pr.new/@tiptap/extension-heading@6917

@tiptap/extension-horizontal-rule

npm i https://pkg.pr.new/@tiptap/extension-horizontal-rule@6917

@tiptap/extension-image

npm i https://pkg.pr.new/@tiptap/extension-image@6917

@tiptap/extension-invisible-characters

npm i https://pkg.pr.new/@tiptap/extension-invisible-characters@6917

@tiptap/extension-italic

npm i https://pkg.pr.new/@tiptap/extension-italic@6917

@tiptap/extension-link

npm i https://pkg.pr.new/@tiptap/extension-link@6917

@tiptap/extension-mathematics

npm i https://pkg.pr.new/@tiptap/extension-mathematics@6917

@tiptap/extension-list

npm i https://pkg.pr.new/@tiptap/extension-list@6917

@tiptap/extension-mention

npm i https://pkg.pr.new/@tiptap/extension-mention@6917

@tiptap/extension-node-range

npm i https://pkg.pr.new/@tiptap/extension-node-range@6917

@tiptap/extension-ordered-list

npm i https://pkg.pr.new/@tiptap/extension-ordered-list@6917

@tiptap/extension-paragraph

npm i https://pkg.pr.new/@tiptap/extension-paragraph@6917

@tiptap/extension-strike

npm i https://pkg.pr.new/@tiptap/extension-strike@6917

@tiptap/extension-subscript

npm i https://pkg.pr.new/@tiptap/extension-subscript@6917

@tiptap/extension-superscript

npm i https://pkg.pr.new/@tiptap/extension-superscript@6917

@tiptap/extension-table

npm i https://pkg.pr.new/@tiptap/extension-table@6917

@tiptap/extension-table-of-contents

npm i https://pkg.pr.new/@tiptap/extension-table-of-contents@6917

@tiptap/extension-text

npm i https://pkg.pr.new/@tiptap/extension-text@6917

@tiptap/extension-text-align

npm i https://pkg.pr.new/@tiptap/extension-text-align@6917

@tiptap/extension-typography

npm i https://pkg.pr.new/@tiptap/extension-typography@6917

@tiptap/extension-underline

npm i https://pkg.pr.new/@tiptap/extension-underline@6917

@tiptap/extension-text-style

npm i https://pkg.pr.new/@tiptap/extension-text-style@6917

@tiptap/extension-unique-id

npm i https://pkg.pr.new/@tiptap/extension-unique-id@6917

@tiptap/extension-youtube

npm i https://pkg.pr.new/@tiptap/extension-youtube@6917

@tiptap/extensions

npm i https://pkg.pr.new/@tiptap/extensions@6917

@tiptap/html

npm i https://pkg.pr.new/@tiptap/html@6917

@tiptap/react

npm i https://pkg.pr.new/@tiptap/react@6917

@tiptap/pm

npm i https://pkg.pr.new/@tiptap/pm@6917

@tiptap/starter-kit

npm i https://pkg.pr.new/@tiptap/starter-kit@6917

@tiptap/static-renderer

npm i https://pkg.pr.new/@tiptap/static-renderer@6917

@tiptap/vue-2

npm i https://pkg.pr.new/@tiptap/vue-2@6917

@tiptap/suggestion

npm i https://pkg.pr.new/@tiptap/suggestion@6917

@tiptap/vue-3

npm i https://pkg.pr.new/@tiptap/vue-3@6917

commit: e17bf4b

@arnaugomez arnaugomez requested a review from Copilot September 5, 2025 11:34
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR introduces a new declarative React component API for Tiptap that provides a more ergonomic, component-first approach to editor integration while maintaining backward compatibility with the existing imperative API.

  • Adds new <Tiptap /> component with context-based editor sharing and subcomponents for content, menus, and loading states
  • Introduces new hooks (useTiptap, useTiptapState) for accessing editor state in child components
  • Improves robustness in core focus command with better error handling for unmounted editor views

Reviewed Changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.

File Description
packages/react/src/index.ts Exports the new Tiptap component and related utilities
packages/react/src/Tiptap.tsx Implements the complete new React integration with context, components, and hooks
packages/core/src/commands/focus.ts Adds try-catch error handling for view.hasFocus() when view is not mounted
.changeset/react-tiptap-new-setup.md Documents the new React integration feature with usage examples and migration guidance

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

Copy link
Contributor

@arnaugomez arnaugomez left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I love this approach, it could make my code simpler.

I'd like to ask whether the isCreated property is necessary. Another doubt I have is whether the Tiptap component could be called TiptapProvider to let the React developer know that it is a context provider

Copy link
Contributor

@arnaugomez arnaugomez left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there is some overlap between this feature and this one:

https://tiptap.dev/docs/editor/getting-started/install/react#using-the-editorcontext

@bdbch
Copy link
Member Author

bdbch commented Sep 5, 2025

I think there is some overlap between this feature and this one:

https://tiptap.dev/docs/editor/getting-started/install/react#using-the-editorcontext

Yes - this will also become obsolete. It was the first draft at implementing React Context but since you can do:

  1. Manual creation of useEditor without any context
  2. Manual creation of useEditor and pass it to <EditorContext.Provider>
  3. Automatic creation by using <EditorProvider content="" extensions={[]} />

I wanted to streamline it and make it more straight forward. So with 4.0.0 I'd get rid of at least 2 and 3.

Users should still be able to just create instances via useEditor and pass it to the EditorContent component BUT the <Tiptap /> approach should become the new React standard for Tiptap.

@bdbch
Copy link
Member Author

bdbch commented Sep 5, 2025

Another doubt I have is whether the Tiptap component could be called TiptapProvider to let the React developer know that it is a context provider

I understand your thought but I think lots of other libraries already do something similar (just checking Radix or FloatingUI for example - you just use DropdownMenu, not DropdownMenuProvider).

We could allow both - <Tiptap> or <Tiptap.Provider> as an additional mapping but that could also confuse people.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants